
unit MMK;

interface
  uses Variants;

const
  MAX_MESS_SIZE     = 256;
  MAX_BUFFER_SIZE   = 256;
  LAST_BUFFER_INDEX = MAX_BUFFER_SIZE - 1;
  SYNCHRO_START     = 0;
  SYNCHRO_END       = 0;
  MMK_READ_COMMAND  = 1;
  MMK_TEMP_ADDRESS  = 14;
  MMK_TEMP_SIZE     = 4;

  mmkFSTART         = $02;
  mmkFSTOP          = $04;
  mmkFEND           = $04;
  mmkFESC           = $10;

  mmkCmdRead        = 1;
  mmkCmdWrite       = 2;

type
{
  CRC_16 = record
  case byte of
    0: (bytes: array [0..1] of byte);
    1: (word: Word);
  end;

  mmkHeader = record
//    sSynchro: Word;
    dAddress: Byte;
    Command: Byte;
    Data : Integer;
//    Data: array of Byte;
  end;
  pmmkHeader = ^mmkHeader;

  mmkEnding = record
    CRC: Word;
    eSynchro: Word;
  end;
  pmmkEnding = ^mmkEnding;

  TmmkMessage = class(TObject)
  private
    Data: array[0..MAX_MESS_SIZE - 1] of Byte;
    pHeader : pmmkHeader;
    pEnding : pmmkEnding;
    
  public
    constructor Create; overload;
    constructor Create(Target, Command: byte); overload;
    destructor Destroy;
    procedure Copy(pData: Pointer; cData: byte);
    function GetAddress: Byte;
    function GetData: Integer;
    procedure SetAddress(Target: byte);
    procedure SetCommand(Command: Byte);
  end;
}
  TmmkCallBack = procedure(Device : byte; Func : byte; Data : real; Status : byte);

  TmmkBuffer = class(TObject)
  private
    index : Integer;
    StuffFlag : Boolean;
    lastAddr : Word;

    procedure mmkStartEvent;
    procedure mmkStopEvent;
    procedure mmkOverLoadErrorEvent;
    function InsertByte(data : Byte):Boolean;
    procedure mmkCRCbyte(data : Byte; var Crc_H, Crc_L : Byte);
    procedure mmkCRCmess(pData : pointer; count : Byte; var Crc_L, Crc_H : Byte);

  public
    Buffer : array [0..MAX_BUFFER_SIZE-1] of Byte;
    ReturnData : TmmkCallBack;

    constructor Create;
    procedure ReadByte(data : Byte);
    function ReadRequest(Device : Byte; dAddr : Word; Count : Byte) : Byte;
  end;

//function CalcCRC( buffer : Pointer; count : Byte; CRC : CRC_16) : CRC_16;

procedure InitArray;

var
  tArray : array [0..MAX_BUFFER_SIZE-1] of Byte;

implementation

procedure InitArray;
begin
  tArray[0] := $10;
  tArray[1] := $02;
  tArray[2] := $0a;
  tArray[3] := $01;
  tArray[4] := $00;
  tArray[5] := $10;
  tArray[6] := $10;
  tArray[7] := $04;
  tArray[8] := $f7;
  tArray[9] := $2b;
  tArray[10] := $10;
  tArray[11] := $04;
//  tArray[] := $;
end;

{ TmmkBuffer }

function TmmkBuffer.ReadRequest(Device: Byte; dAddr: Word; Count: Byte): Byte;
var
  tBuffer : array [0..MAX_BUFFER_SIZE-1] of Byte;
  i,k : Byte;
  CrcH, CrcL : Byte;
begin
  lastAddr := dAddr;
  tBuffer[0] := Device;
  tBuffer[1] := mmkCmdRead;
  tBuffer[2] := Hi(dAddr);
  tBuffer[3] := Lo(dAddr);
  tBuffer[4] := Count;
  mmkCRCmess(Addr(tBuffer[0]), 5, tBuffer[6], tBuffer[5]);

  Buffer[0] := mmkFESC;
  Buffer[1] := mmkFSTART;  
  k := 2;
  for i := 0 to 6 do begin
    Buffer[k] := tBuffer[i];
    if Buffer[k] = mmkFESC then begin
      inc(k);
      Buffer[k] := mmkFESC;
    end;
    Inc(k);
  end;
  Buffer[k] := mmkFESC;
  inc(k);
  Buffer[k] := mmkFEND;
  Result := k + 1;
end;

procedure TmmkBuffer.mmkCRCbyte(data: Byte; var Crc_H, Crc_L: Byte);
var
  temp : Byte;
  i : Integer;
  Flag1, Flag2 : Boolean;
begin
  temp := data;
  for i := 0 to 7 do begin
    if Crc_H >= $80 then begin
      Crc_H := Crc_H xor $C0;
      Crc_L := Crc_L xor $02;
      temp := temp xor $80;
    end;

    if temp >= $80 then
      begin
      Flag1 := True;
      temp := temp and $7f;
      end
    else Flag1 := False;
    temp := temp shl 1;

    if Crc_L >= $80 then
      begin
      Flag2 := True;
      Crc_L := Crc_L and $7f;
      end
    else Flag2 := False;
    Crc_L := Crc_L shl 1;

    if Crc_H >= $80 then Crc_H := Crc_H and $7f;
    Crc_H := Crc_H shl 1;
    if Flag1 then Crc_L := Crc_L + 1;
    if Flag2 then Crc_H := Crc_H + 1;
  end;
end;

procedure TmmkBuffer.mmkCRCmess(pData : pointer; count : Byte; var Crc_L, Crc_H : Byte);//: Boolean;
var
  i : Integer;
  data : ^Byte;
begin
  Crc_L := 0;
  Crc_H := 0;
  data := pData;
  for i := 0 to count - 1 do begin
    mmkCRCbyte(data^, Crc_H, Crc_L);
    inc(data);
  end;
  mmkCRCbyte(0, Crc_H, Crc_L);
  mmkCRCbyte(0, Crc_H, Crc_L);
end;

constructor TmmkBuffer.Create;
begin
  inherited;

  StuffFlag := False;
  index := 0;

end;

procedure TmmkBuffer.ReadByte(data: Byte);
begin
  if StuffFlag = True then begin
    case data of
      mmkFSTOP  : mmkStopEvent;
      mmkFESC   : InsertByte(data);
    else
      mmkStartEvent;
    end;
    StuffFlag := False;
  end
  else begin
    if data = mmkFESC then StuffFlag := True
    else begin
      if InsertByte(data) = False then mmkOverLoadErrorEvent;
    end;
  end;
end;

function TmmkBuffer.InsertByte(data: Byte): Boolean;
begin
  Result := False;
  if index < MAX_BUFFER_SIZE then begin
    Buffer[index] := data;
    inc(index);
    Result := True;
  end;
end;

procedure TmmkBuffer.mmkOverLoadErrorEvent;
begin

end;

procedure TmmkBuffer.mmkStartEvent;
begin
  index := 0;
end;

procedure TmmkBuffer.mmkStopEvent;
var
  Crc_L, Crc_H : Byte;
  Data : real;
begin
  mmkCRCmess(Addr(Buffer[0]), index - 2, Crc_L, Crc_H);
  if (Buffer[index - 2] = Crc_H) and (Buffer[index - 1] = Crc_L) then begin
    case lastAddr of
      2 : begin
        Data := Buffer[6] * 256 * 256 * 256;
        Data := Data + (Buffer[7] * 256 * 256);
        Data := Data + (Buffer[8] * 256);
        Data := (Data + Buffer[9])/100;
        ReturnData(Buffer[2], 6, Data, 0);

        Data := (Buffer[10] * 256 + Buffer[11])/100;
        ReturnData(Buffer[2], 10, Data, 0);

        Data := (Buffer[12] * 256 + Buffer[13])/10;
        ReturnData(Buffer[2], 12, Data, 0);
      end;
      6 : begin                                 // Pressure
        Data := Buffer[2] * 256 * 256 * 256;
        Data := Data + (Buffer[3] * 256 * 256);
        Data := Data + (Buffer[4] * 256);
        Data := (Data + Buffer[5])/100;
        ReturnData(Buffer[2], 6, Data, 0);
      end;
      10 : begin  // Temp
        Data := (Buffer[2] * 256 + Buffer[3])/100;
        ReturnData(Buffer[2], 10, Data, 0);
      end;
      12 : begin
        Data := (Buffer[2] * 256 + Buffer[3])/10;
        ReturnData(Buffer[2], 6, Data, 0);
      end;
    end;
  end;
end;

end.
